#include "hashMap.h"

#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <strings.h>

// 哈希函数
static uint32_t hash(const void *key, int len, uint32_t seed)
{
    const uint32_t m = 0x5bd1e995;
    const int r = 24;
    uint32_t h = seed ^ len;
    const unsigned char *data = (const unsigned char *)key;

    while (len >= 4)
    {
        uint32_t k = *(uint32_t *)data;
        k *= m;
        k ^= k >> r;
        k *= m;
        h *= m;
        h ^= k;
        data += 4;
        len -= 4;
    }

    switch (len)
    {
    case 3:
        h ^= data[2] << 16;
    case 2:
        h ^= data[1] << 8;
    case 1:
        h ^= data[0];
        h *= m;
    };

    h ^= h >> 13;
    h *= m;
    h ^= h >> 15;

    return h;
}

system_error_code_t hash_map_init(hash_map_t *map, int size)
{
    // 参数检查
    if (map == NULL || size <= 0)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 分配哈希桶数组
    map->buckets = (hash_node_t **)calloc(size, sizeof(hash_node_t *));
    if (map->buckets == NULL)
    {
        return SYSTEM_ERR_OUT_OF_MEMORY;
    }

    // 初始化哈希表成员
    map->seed = (uint32_t)time(NULL); // 使用时间戳作为哈希种子
    map->size = size;
    map->count = 0; // 初始化计数器

    return SYSTEM_ERR_OK; // 初始化成功
}

system_error_code_t hash_map_get(hash_map_t *map, int fd, intptr_t *out_ring_queue_index)
{
    // 参数检查
    if (map == NULL || out_ring_queue_index == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 计算哈希值和桶索引
    uint32_t hash_value = hash(&fd, sizeof(fd), map->seed);
    int bucket_index = hash_value % map->size;

    // 遍历链表查找对应的文件描述符
    hash_node_t *current_node = map->buckets[bucket_index];
    while (current_node != NULL)
    {
        if (current_node->fd == fd)
        {
            // 找到对应的文件描述符，返回环形队列索引
            *out_ring_queue_index = current_node->ring_queue_index;
            return SYSTEM_ERR_OK; // 查找成功
        }
        current_node = current_node->next;
    }

    return SYSTEM_ERR_HASHMAP_NOT_FOUND;
}

system_error_code_t hash_map_put(hash_map_t *map, int fd, intptr_t ring_queue_index)
{
    // 参数检查
    if (map == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 计算哈希值和桶索引
    uint32_t hash_value = hash(&fd, sizeof(fd), map->seed);
    int bucket_index = hash_value % map->size;

    // 检查是否已经存在该文件描述符，若存在则更新其环形队列索引
    hash_node_t *current_node = map->buckets[bucket_index];
    while (current_node != NULL)
    {
        if (current_node->fd == fd)
        {
            // 更新环形队列索引
            current_node->ring_queue_index = ring_queue_index;
            return SYSTEM_ERR_HASHMAP_ALREADY_EXISTS; // 返回已存在
        }
        current_node = current_node->next;
    }

    // 创建新的哈希节点
    hash_node_t *new_node = (hash_node_t *)malloc(sizeof(hash_node_t));
    if (new_node == NULL)
    {
        return SYSTEM_ERR_OUT_OF_MEMORY;
    }

    // 初始化新节点
    bzero(new_node, sizeof(hash_node_t));
    new_node->fd = fd;
    new_node->ring_queue_index = ring_queue_index;
    new_node->next = map->buckets[bucket_index];

    // 插入新节点到哈希桶链表头部
    map->buckets[bucket_index] = new_node;
    map->count++; // 只有在插入新节点时才增加计数

    return SYSTEM_ERR_OK;
}

system_error_code_t hash_map_remove(hash_map_t *map, int fd)
{
    // 参数检查
    if (map == NULL)
    {
        return SYSTEM_ERR_INVALID_ARGUMENT;
    }

    // 计算哈希值和桶索引
    uint32_t hash_value = hash(&fd, sizeof(fd), map->seed);
    int bucket_index = hash_value % map->size;

    // 遍历链表查找并移除对应的文件描述符节点
    hash_node_t *current_node = map->buckets[bucket_index];
    hash_node_t *prev_node = NULL;

    while (current_node != NULL)
    {
        if (current_node->fd == fd)
        {
            // 找到对应的文件描述符节点，进行移除
            if (prev_node == NULL)
            {
                // 移除的是链表头节点
                map->buckets[bucket_index] = current_node->next;
            }
            else
            {
                // 移除的是非头节点
                prev_node->next = current_node->next;
            }

            // 释放节点内存
            free(current_node);
            map->count--; // 成功移除节点后减少计数
            return SYSTEM_ERR_OK;
        }
        prev_node = current_node;
        current_node = current_node->next;
    }

    return SYSTEM_ERR_HASHMAP_NOT_FOUND;
}